package org.zoomdev.zoom.event.modules;

import org.apache.commons.lang3.StringUtils;
import org.zoomdev.zoom.aop.Interceptor;
import org.zoomdev.zoom.aop.Invoker;
import org.zoomdev.zoom.aop.factory.AnnotationInterceptorFactory;
import org.zoomdev.zoom.async.AsyncService;
import org.zoomdev.zoom.common.exceptions.ZoomException;
import org.zoomdev.zoom.event.EventService;
import org.zoomdev.zoom.event.annotations.EventNotifier;

import java.lang.reflect.Method;
import java.util.List;

public class EventNotifierInterceptorFactory extends AnnotationInterceptorFactory<EventNotifier> {
    private final EventService eventService;

    private final AsyncService asyncService;

    public EventNotifierInterceptorFactory(EventService eventService, AsyncService asyncService) {
        this.eventService = eventService;
        this.asyncService = asyncService;
    }

    static class EventResultMethodInterceptor implements Interceptor {
        private final EventService eventService;

        private final AsyncService asyncService;

        private final String name;

        private final boolean async;

        public EventResultMethodInterceptor(EventService eventService, AsyncService asyncService, String name, boolean async) {
            this.eventService = eventService;
            this.asyncService = asyncService;
            this.name = name;
            this.async = async;
        }


        @Override
        public Object intercept(Invoker invoker, Method method, Object target, Object[] args) throws Throwable {
            Object result = invoker.invoke(target, args);
            if (async) {
                asyncService.run(() -> eventService.notifyObservers(name, result));
            } else {
                eventService.notifyObservers(name, result);
            }

            return result;
        }
    }

    @Override
    protected void createInterceptor(EventNotifier annotation, Class<?> targetClass, Method method, List<Interceptor> interceptors) {
        if (StringUtils.isEmpty(annotation.name())) {
            throw new ZoomException("事件通知必须给出通知事件名称" + method);
        }
        interceptors.add(new EventResultMethodInterceptor(eventService, asyncService, annotation.name(), annotation.async()));
    }
}
